package com.ext.aic.box;

import android.accessibilityservice.AccessibilityService;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.text.TextUtils;
import android.view.accessibility.AccessibilityNodeInfo;

import com.ext.aic.events.OnAccessibilityServiceEvent;
import com.ext.aic.events.OnSoftKeyboardListener;
import com.ext.aic.utils.BoxUtils;
import com.ext.aic.utils.FilteringUtils;
import com.eyinfo.android_pure_utils.HandlerManager;
import com.eyinfo.android_pure_utils.events.Action0;
import com.eyinfo.android_pure_utils.events.Action1;
import com.eyinfo.android_pure_utils.events.RunnableParamsN;
import com.eyinfo.android_pure_utils.observable.ObservableComponent;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class WindowManager {

    private Map<Integer, OnSoftKeyboardListener> softKeyboardMap = new HashMap<>();
    private Map<Integer, Action0> hideKeyboardMap = new HashMap<>();
    private Handler handler = new Handler();
    private Runnable pendingPasteRunnable;

    protected void onCreate() {

    }

    static class SoftKeyboardTaskParams {
        public int softKeyboardCode;
        public CountDownLatch latch;
    }

    protected void awaitShowSoftKeyboard(OnSoftKeyboardListener listener) {
        OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
        softKeyboardMap.put(listener.hashCode(), listener);
        int softKeyboardHeight = serviceEvent.getSoftKeyboardHeight();
        if (softKeyboardHeight > 0) {
            delayShowKeyboard(700, listener);
        } else {
            CountDownLatch latch = new CountDownLatch(1);
            SoftKeyboardTaskParams params = new SoftKeyboardTaskParams();
            params.latch = latch;
            params.softKeyboardCode = listener.hashCode();
            keyboardAwaitComponent.build(params);
            try {
                boolean await = latch.await(1000, TimeUnit.MILLISECONDS);
            } catch (Exception e) {
                latch.countDown();
                Thread.currentThread().interrupt();
            }
        }
    }

    private ObservableComponent<Integer, SoftKeyboardTaskParams> keyboardAwaitComponent = new ObservableComponent<Integer, SoftKeyboardTaskParams>() {
        @Override
        protected Integer subscribeWith(SoftKeyboardTaskParams... params) throws Exception {
            OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
            SoftKeyboardTaskParams param = params[0];
            int softHeight = 0;
            while (softHeight <= 0) {
                softHeight = serviceEvent.getSoftKeyboardHeight();
                if (softHeight > 0) {
                    param.latch.countDown();
                    break;
                }
                SystemClock.sleep(500);
            }
            return softHeight;
        }

        @Override
        protected void nextWith(Integer softHeight, SoftKeyboardTaskParams... params) {
            SoftKeyboardTaskParams param = params[0];
            OnSoftKeyboardListener keyboardListener = softKeyboardMap.remove(param.softKeyboardCode);
            if (keyboardListener != null) {
                OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
                keyboardListener.onSoftKeyboardShow(serviceEvent.getSoftKeyboardHeight());
                softKeyboardMap.remove(keyboardListener.hashCode());
            }
        }
    };

    private void delayShowKeyboard(int delay, OnSoftKeyboardListener listener) {
        HandlerManager.getInstance().postDelayed(new RunnableParamsN<Object>() {
            @Override
            public void run(Object... objects) {
                if (listener != null) {
                    OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
                    listener.onSoftKeyboardShow(serviceEvent.getSoftKeyboardHeight());
                    softKeyboardMap.remove(listener.hashCode());
                }
            }
        }, delay);
    }

    protected void assignEditText(AccessibilityNodeInfo editNode, String content, Action1<Boolean> successCall) {
        try {
            if (TextUtils.isEmpty(content)) {
                return;
            }
            OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
            AccessibilityService service = serviceEvent.getService();
            content = FilteringUtils.getInstance().filterRepeatedContent(content);
            ClipboardManager clipboard = (ClipboardManager) service.getSystemService(Context.CLIPBOARD_SERVICE);
            ClipData clip = ClipData.newPlainText("label", content);
            clipboard.setPrimaryClip(clip);
            // 取消之前未执行的粘贴任务
            if (pendingPasteRunnable != null) {
                handler.removeCallbacks(pendingPasteRunnable);
            }
            String finalContent = content;
            pendingPasteRunnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        Bundle pasteArgs = new Bundle();
                        pasteArgs.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, finalContent);
                        if (successCall != null) {
                            successCall.call(clipboard.hasPrimaryClip());
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            };
            // 延迟100毫秒执行，合并多次调用
            handler.postDelayed(pendingPasteRunnable, 100);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void awaitHideSoftKeyboardFinish(Action0 successCall) {
        OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
        RegisterAccessibilityService service = serviceEvent.getService();
        boolean status = service.hideKeyboardViaBackKey();
        if (status) {
            hideKeyboardMap.put(successCall.hashCode(), successCall);
            CountDownLatch latch = new CountDownLatch(1);
            SoftKeyboardTaskParams params = new SoftKeyboardTaskParams();
            params.latch = latch;
            params.softKeyboardCode = successCall.hashCode();
            hideKeyboardAwaitComponent.build(params);
            try {
                boolean await = latch.await(1000, TimeUnit.MILLISECONDS);
            } catch (Exception e) {
                latch.countDown();
                Thread.currentThread().interrupt();
                if (successCall != null) {
                    successCall.call();
                }
            }
        } else {
            handler.postDelayed(new HideSoftKeyboardFinishRunnable(successCall), 800);
        }
    }

    private ObservableComponent<Integer, SoftKeyboardTaskParams> hideKeyboardAwaitComponent = new ObservableComponent<Integer, SoftKeyboardTaskParams>() {
        @Override
        protected Integer subscribeWith(SoftKeyboardTaskParams... params) throws Exception {
            OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
            SoftKeyboardTaskParams param = params[0];
            int softHeight = serviceEvent.getSoftKeyboardHeight(true);
            while (softHeight > 0) {
                SystemClock.sleep(200);
                softHeight = serviceEvent.getSoftKeyboardHeight(true);
            }
            param.latch.countDown();
            return softHeight;
        }

        @Override
        protected void nextWith(Integer softHeight, SoftKeyboardTaskParams... params) {
            SoftKeyboardTaskParams param = params[0];
            Action0 remove = hideKeyboardMap.remove(param.softKeyboardCode);
            handler.postDelayed(new HideSoftKeyboardFinishRunnable(remove), 800);
        }
    };

    static class HideSoftKeyboardFinishRunnable implements Runnable {

        private Action0 successCall;

        public HideSoftKeyboardFinishRunnable(Action0 successCall) {
            this.successCall = successCall;
        }

        @Override
        public void run() {
            if (successCall != null) {
                successCall.call();
            }
        }
    }
}
